﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;
using System.AddIn;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using BlueCurve.Common;
using BlueCurve.IndexationContract;
using BlueCurve.WebCrawlerRequest;


namespace Addins.Html
{
    /// <summary>
    /// Class mère de l'addin
    /// </summary>
    [AddIn("AddinsHtml",
    Version = "1.0.0.0",
    Description = "This addin can index html document",
    Publisher = "BlueCurve Project Team")]
    public class AddinsHtml : BlueCurve.AddinView.AddinFileViewAddinsSide
    {
        /// <summary>
        /// Objet de la common lib
        /// </summary>
        private HTML2Text m_common = new HTML2Text();
        /// <summary>
        /// Contiens les méta données de la page web
        /// </summary>
        private Dictionary<string, string> m_metadatas = new Dictionary<string, string>();

        /// <summary>
        /// Fonction principale de l'AddIn
        /// </summary>
        /// <param name="requeststate">Objet RequestState</param>
        /// <param name="location">Chemin d'accès du fichier</param>
        /// <returns>IndexationData</returns>
        public override IndexationData IndexerLoader(RequestState requeststate, string location)
        {
            IndexationData indexdata = new IndexationData() { IsDesktop = false };
            string rawcontent = null;
            try
            {
                // Ecriture du fichier temporaire
                File.WriteAllBytes(string.Concat(location, @"\data.bin"), requeststate.GetBuffer());

                // Lecture du fichier avec détection d'un eventuel tag bom :)
                using (StreamReader reader = new StreamReader(File.Open(string.Concat(location, @"\data.bin"), FileMode.Open, FileAccess.Read, FileShare.None), m_common.DetectTagBom(string.Concat(location, @"\data.bin"))))
                {
                    rawcontent = reader.ReadToEnd();
                    reader.Close();
                }
                
                // Détection de l'encodage du document définit par le charset
                // Si besoin est le document est convertit vers utf8
                Encoding _charset = m_common.DetectHtmlEncoding(rawcontent);
                if (_charset != null && !_charset.CodePage.Equals(Encoding.UTF8.CodePage))
                {
                    rawcontent = m_common.ConvertEncodingFromMemoryToUtf8(_charset.CodePage, ref rawcontent);
                }
                else
                {
                    // Encodage interne du document
                    Encoding _internal = m_common.DetectEncoding(string.Concat(location, @"\data.bin"));
                    if (_internal != null)
                        rawcontent = m_common.ConvertEncodingFromMemoryToUtf8(_internal.CodePage, ref rawcontent);
                    else
                        rawcontent = m_common.ConvertEncodingFromMemoryToUtf8(Encoding.Unicode.CodePage, ref rawcontent);
                }

                // Récupération des informations
                // permettant de savoir si la requête à été redirigé
                XDocument doc = XDocument.Load(location + @"\info.xml");
                var x = from i in doc.Elements()
                        select new
                        {
                            Uri = i.Element("url").Value,
                            Location = i.Element("location").Value
                        };                

                foreach (var t in x)
                {
                    if (!string.IsNullOrEmpty(t.Location))
                    {
                        indexdata.Path = t.Location;
                        indexdata.OldPath = t.Uri;
                    }
                    else
                    {
                        indexdata.Path = t.Uri;
                    }
                }

                // Récupération du texte du document 
                // nettoyé de tout balisage html
                indexdata.Text = m_common.Stripspaces(m_common.ConvertHtml2TextFromHtmlString(ref rawcontent));

                // Récupération de la date de dernière modification du document
                indexdata.LastModified = DateTime.Parse(requeststate.Headers[HttpResponseHeader.LastModified]);

                // Récupération de la date du document
                indexdata.Size = Convert.ToInt32(requeststate.Headers[HttpResponseHeader.ContentLength]) / 1024;

                // Récuperation du type mime
                indexdata.ContentType = requeststate.Headers[HttpResponseHeader.ContentType].Split(';')[0].ToLower(CultureInfo.InvariantCulture);

                // Récupération du titre
                indexdata.Title = m_common.GetHtmlTitle(ref rawcontent) ?? "Untitled document";

                // Récupération de la description
                indexdata.Description = m_common.GetHtmlMeta(ref rawcontent, "description");

                // Récupération des mots clefs
                indexdata.KeyWords = m_common.GetHtmlMeta(ref rawcontent, "keywords");

                // Récupération du tag revisit-after
                indexdata.RevisitAfter = Convert.ToInt32(m_common.GetHtmlMeta(ref rawcontent, "revisit-after"));

                // Recherche de la langue
                indexdata.Language = m_common.FindDocumentLanguage(ref rawcontent);

                if (string.IsNullOrEmpty(indexdata.Description))
                    indexdata.Description = m_common.GetHtmlMeta(ref rawcontent, "DC.Description");

                if (string.IsNullOrEmpty(indexdata.KeyWords))
                    indexdata.KeyWords = m_common.GetHtmlMeta(ref rawcontent, "DC.Subject.Keywords");
                                
                // Extraction des métadonnées
                this.GetMetaDatas(ref rawcontent, ref indexdata);
                
                // Extraction des liens hypertextes
                m_common.GetHyperTextLinks(ref rawcontent).ForEach(
                    delegate(string uri)
                    {
                        indexdata.Links.Add(new Uri(new Uri(indexdata.Path), m_common.NormalizeLink(uri)).ToString());
                    });

                // Extraction des liens hypertextes et de leur titre (en ayant effectivement un)
                foreach (KeyValuePair<string, string> pair in m_common.GetHyperTextLinksAndLinksTitle(ref rawcontent))
                    indexdata.LinksAndAnchor.Add(new Uri(new Uri(indexdata.Path), m_common.NormalizeLink(pair.Key)).ToString(), pair.Value);

                       // Extraction des flux Rss
                List<string> _rss = m_common.GetRssFeeds(ref rawcontent);
                _rss.ForEach(
                    delegate(string link)
                    {
                        indexdata.RssFeeds.Add(new Uri(new Uri(indexdata.Path), link).ToString());
                    });
                
                return indexdata;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }


        /// <summary>
        /// Récupère les métas données Dublin core
        /// </summary>
        /// <param name="content">Contenue du fichier</param>
        /// <param name="indexdata">Données pour l'indexation</param>
        private void GetMetaDatas(ref string content, ref IndexationData indexdata)
        {
            string Temp = null;
            // Créateur de la page web ou du site
            Temp = m_common.GetHtmlMeta(ref content, "DC.Creator");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Creator", new Meta(Temp, Tokenize.YES));

            // Sujet de la page
            Temp = m_common.GetHtmlMeta(ref content, "DC.Subject");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Subject", new Meta(Temp, Tokenize.YES));

            // Nom de celui ou celle qui à publié la page
            Temp = m_common.GetHtmlMeta(ref content, "DC.Publisher");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Publisher", new Meta(Temp, Tokenize.YES));

            // Ressource dont dérive le document : le document peut découler en totalité ou en partie de la ressource en question. 
            // Il est recommandé d'utiliser une dénomination formelle des ressources, par exemple leur URI.
            // Exemple bibliothèque nationale de france BnF 8-Yf-118
            Temp = m_common.GetHtmlMeta(ref content, "DC.Source");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Source", new Meta(Temp, Tokenize.YES));

            // Langue dans laquelle est rédigé le document
            Temp = m_common.GetHtmlMeta(ref content, "DC.Language");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Language", new Meta(Temp, Tokenize.YES));

            // Lien vers une ressource liée
            Temp = m_common.GetHtmlMeta(ref content, "DC.Relation");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Relation", new Meta(Temp, Tokenize.YES));

            // Portée du document : la portée inclut un domaine géographique, un laps de temps, ou une juridiction
            // (nom d'une entité administrative). Il est recommandé d'utiliser des représentations normalisées de ces
            // types de données. Le type de couverture peut être précisé :
            Temp = m_common.GetHtmlMeta(ref content, "DC.Coverage");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Coverage", new Meta(Temp, Tokenize.YES));

            // Droits relatifs à la ressource : permet de donner des informations sur le statut des droits du document
            // par exemple la présence d'un copyright, ou un lien vers le détenteur des droits.
            // L'absence de cet élément ne présume pas que le document est libre de droits. 
            Temp = m_common.GetHtmlMeta(ref content, "DC.Rights");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Rights", new Meta(Temp, Tokenize.YES));

            // Date de création
            Temp = m_common.GetHtmlMeta(ref content, "DC.Date.Created");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Date.Created", new Meta(Temp, Tokenize.YES));

            // Date de publication
            Temp = m_common.GetHtmlMeta(ref content, "DC.Date.Issued");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Date.Issued", new Meta(Temp, Tokenize.YES));

            // Date de modification
            Temp = m_common.GetHtmlMeta(ref content, "DC.Date.Modified");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Modified", new Meta(DateTime.Parse(Temp).ToString(), Tokenize.YES));

            // Date ou période de mise à disposition
            Temp = m_common.GetHtmlMeta(ref content, "DC.Date.Available");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Available", new Meta(DateTime.Parse(Temp).ToString(), Tokenize.YES));

            // Date où le document a été soumis (par exemple, soumis à un comité de lecture s'il s'agit d'un article). 
            Temp = m_common.GetHtmlMeta(ref content, "DC.Date.DateSubmitted");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Datesubmitted", new Meta(DateTime.Parse(Temp).ToString(), Tokenize.YES));

            // Contributeur
            Temp = m_common.GetHtmlMeta(ref content, "DC.contributor");
            if (!string.IsNullOrEmpty(Temp))
                indexdata.MetaDatas.Add("DC.Contributor", new Meta(Temp, Tokenize.YES));
        }
    }
}
